KinematicBody

KinematicBody lets you code custom 3D movement

KinematicBody is the ideal node for tight control of objects interacting with the game world.

Characters in 3D platformers and FPS games, moving platforms, and anything else you want to control that also needs to collide with other game entities are great candidates for KinematicBody.

If you want more realistic Newtonian physics and to let the physics engine calculate movement for you, you’ll want to use RigidBody instead.

In this guide, you will learn:

We’ll wrap up with your questions, troubleshooting help, and tips.

Contents:

Setting up a KinematicBody

Like other physics bodies in Godot, a KinematicBody requires one or more CollisionShape or CollisionPolygon nodes as children.

The collision nodes define the shape the physics engine uses to check for collisions with the environment.

You can always use more than one shape to approximate the shape of your character or entity.

KinematicBody’s key features

KinematicBody comes packed with functions to create character controllers with ease:

Moving and sliding

The most valuable function of a KinematicBody is move_and_slide().

It takes a velocity and moves your entity accordingly in one frame.

move_and_slide() applies delta time delta internally, meaning bodies move at the same speed regardless of the framerate the user is experiencing.

If the body hits an obstacle, the function slides the body against it.

Technically, it takes the leftover motion at the collision point and projects the remaining velocity alongside it.

If any motion remains after colliding, the node repeats the operation up to 5 times, allowing your entity to slide smoothly along curved obstacles. You can adjust this with the max_slides parameter of move_and_slide().

move_and_slide() also takes other moving bodies into account. For example, if a character is on a moving platform, both move together.

The move_and_slide_with_snap() function is a more powerful alternative for worlds with slopes. When walking on a slope, you can use it to snap your character to the slope.

You do that using the snap argument, a vector representing a distance to the floor. If your character is too close to the floor, it will snap to it.

Both the move_and_slide() and move_and_slide_with_snap() functions also allow you to define the “up” vector.

This argument helps the engine determine what direction is “up” and, therefore, where the floor, ceilings, and walls are.

Note: We put “up” in quotes because you can use that to reverse gravity in your game, allow characters to move around planets, and more.

You’ll want to change the up vector in a game where you change the direction of gravity, turning the walls and ceiling into the floor. For games that have normal gravity Vector3.UP is the default unit vector pointing upwards on the y-axis.

Game: Super Mario Galaxy

The default value for up is Vector3.ZERO. In this case, the KinematicBody treats all surfaces as a wall.

Coding custom movement and collisions

What if you want a projectile to bounce against surfaces? With move_and_slide(), the projectile slides alongside walls after a collision.

Or perhaps you want a feel you cannot achieve easily with move_and_slide(), like a specific style of character movement.

That’s what move_and_collide() is for. This function moves the body with a motion vector. This is different from move_and_slide(), which instead takes a velocity.

The move_and_collide() function moves the character given that input motion and collides along the way. If a collision occurs, the function returns a KinematicCollision object, providing information about what happened. You can then use that information to code your intended movement.

Godot uses move_and_collide() as a base internally for move_and_slide() and move_and_slide_with_snap().

Getting information about a collision

When collisions occur, you can get detailed information about them. Whether you use move_and_slide() or move_and_collide(), you can get a KinematicCollision instance to know where, when, and between which physics shapes the collision occurred.

If you use move_and_collide() and a collision occurs, the function returns the KinematicCollision instance. We typically store and use it like so:

var collision := move_and_collide(motion)
if collision:
    # ...

With move_and_slide(), as we saw above, the engine may move your body multiple times to smooth out its motion. The function itself returns a new velocity, taking into account any obstacle that affects your body.

If you want collision information, you need to request it. To do so, you’ll use two functions: get_slide_count() and get_slide_collision().

The get_slide_count() function tells you the number of collisions that occurred after calling move_and_slide(). You use it to ensure a given collision exists when calling get_slide_collision(), like so:

move_and_slide(velocity)
for index in get_slide_count():
    var collision := get_slide_collision(index)
    # ...

Checking for the floor, walls, and the ceiling

KinematicBody provides three functions to know if your entity is touching a surface at any point in time:

  1. is_on_floor().
  2. is_on_wall().
  3. is_on_ceiling().

They return true if the body is against the corresponding surface.

These functions only work after moving your KinematicBody and having it collide with that surface. Otherwise, the physics engine assumes your entity is in the air.

If you are using move_and_slide(), you’ll want to apply gravity to your characters even when grounded to ensure they collide with the floor. If you are using move_and_slide_with_snap(), this is not needed as the snapping ensures the ground collision.

You can use those functions to check if the player can jump without a dedicated can_jump variable.

How to use a KinematicBody in practice

Many of these demos build upon the same base code, unlike other node essentials guides.

We created a base script with shared constants, properties, and functions. Some demos extend it and use the base functions or build upon them.

# Example from PlayerPushRigidBody3D.gd
extends BasePlayerPlatformer3D

func _physics_process(delta: float) -> void:
    apply_base_movement(delta)
    push(delta)

We’ll start by covering the base class and how we coded running and jumping before tackling the other ways to use KinematicBody.

Note that we wrote small functions to help you read the code and make it reusable.

We don’t necessarily recommend splitting your code this way in your games; we chose this style for the needs of the node essentials demos and this guide.

Basic 3D Platformer movement

The KinematicBody node requires coding all of your movement logic by yourself. Here, you’ll get a detailed look at a base class for 3D platformer movement.

This code is more fleshed out as we took the time to name all the values we use with exported variables and create functions to make the code readable and reusable in other demos.

In this example, the character can:

The scene relies on one KinematicBody node and a CollisionShape. The AstronautSkin is the animated 3D mesh for the character.

To implement all the mechanics above, we need to tell Godot some values to know how to move our body. We store them as exported variables to make them editable in the Inspector.

export var move_speed := 6.0
export var acceleration := 6.0
export var jump_initial_impulse := 12.0
export var jump_additional_force := 4.5
export var rotation_speed := 12.0
export var snap_length := 0.5
export var do_stop_on_slope := true
export var has_infinite_inertia := true

We then define a function to calculate the character’s motion and move it, which has four steps:

  1. Convert the player’s input to be relative to the 3D Camera.
  2. Calculate the new base velocity.
  3. Check for the character’s jump and landing states and update the velocity if necessary.
  4. Finally, move the character using the move_and_slide_with_snap() function.

Here is the base input and orientating it to be relative to the Camera.

    _move_direction = _get_camera_oriented_input()
func _get_camera_oriented_input() -> Vector3:
    var input_left_right := (
        Input.get_action_strength("move_right")
        - Input.get_action_strength("move_left")
    )
    var input_forward_back := (
        Input.get_action_strength("move_down")
        - Input.get_action_strength("move_up")
    )
    var raw_input := Vector2(input_left_right, input_forward_back)

    var input := Vector3.ZERO
    # This is to ensure that diagonal input isn't stronger than axis aligned input
    input.x = raw_input.x * sqrt(1.0 - raw_input.y * raw_input.y / 2.0)
    input.z = raw_input.y * sqrt(1.0 - raw_input.x * raw_input.x / 2.0)

    input = _camera_controller.global_transform.basis.xform(input)
    return input

Then we calculate the new velocity using the player input.

    # We separate out the y velocity to not interpolate on the gravity
    var y_velocity := _velocity.y
    _velocity.y = 0.0
    _velocity = _velocity.linear_interpolate(_move_direction * move_speed, acceleration * delta)
    _velocity.y = y_velocity

Next, we look at the character’s current state to modify the velocity. It is important to set the snap value to Vector2.ZERO whenever the player jumps. Otherwise, the move_and_slide_with_snap() function keeps the astronaut snapped to the surface in the direction of the snap vector.

    if is_jumping():
        _velocity.y = jump_initial_impulse
        _snap = Vector3.ZERO
        _model.jump()
    elif is_air_boosting():
        _velocity.y += jump_additional_force * delta
    elif is_landing():
        _snap = Vector3.DOWN * snap_length
        _model.land()

You can think of the snap vector like a ray cast from the KinematicBody’s origin.

If it touches the floor, the move_and_slide_with_snap() function snaps the character to the floor.

This function is handy when walking on a slope, preventing the character from hopping down each step.

As you can see, we use some functions we define ourselves to check if the character is jumping, landing, etc.

We wrote them that way to help you read the code and to reuse them across demos.

func is_jumping() -> bool:
    return Input.is_action_just_pressed("jump_3d") and is_on_floor()


func is_air_boosting() -> bool:
    return Input.is_action_pressed("jump_3d") and not is_on_floor() and _velocity.y > 0.0


func is_landing() -> bool:
    return _snap == Vector3.ZERO and is_on_floor()

Back to the apply_base_movement() function, we call move_and_slide_with_snap() to move the character.

    _velocity = move_and_slide_with_snap(
        _velocity, _snap, Vector3.UP, do_stop_on_slope, 4, deg2rad(45), has_infinite_inertia
    )

Updating the visuals

We orient the character model to the direction the player is trying to move in.

    # To not orient quickly to the last input, we save a last strong direction,
    # this also ensures a good normalized value for the rotation basis.
    if _move_direction.length() > 0.2:
        _last_strong_direction = _move_direction.normalized()

    _orient_character_to_direction(_last_strong_direction, delta)

We rotate the model by calculating a new Basis based on the input direction and using the slerp() function to turn towards it smoothly. For more information on working with rotations in 3D, see Using 3D Transforms in the Godot manual.

func _orient_character_to_direction(direction: Vector3, delta: float) -> void:
    var left_axis := Vector3.UP.cross(direction)
    var rotation_basis := Basis(left_axis, Vector3.UP, direction).orthonormalized()
    _model.transform.basis = _model.transform.basis.orthonormalized().slerp(rotation_basis, delta * rotation_speed).scaled(_model.scale)

We handle the rest of the visuals with a separate scene and script: AstronautSkin.tscn and AstronautSkin.gd. We forward the velocity every frame to adjust the animation playback speed and forward jumping and landing events through function calls.

    _model.velocity = _velocity
    if is_jumping():
        _velocity.y = jump_initial_impulse
        _snap = Vector3.ZERO
        _model.jump()
    elif is_air_boosting():
        _velocity.y += jump_additional_force * delta
    elif is_landing():
        _snap = Vector3.DOWN * snap_length
        _model.land()

All the above is a base you can use to create platforming characters and we use it in the following examples.

Stomping enemies

In just a few lines of code, you can extend a base character controller with a stomping mechanic as in Mario games.

To stomp an enemy, we need to check if the player lands on the top of them. If we use box collision shapes, we can directly use the is_on_floor() function.

We loop through all the collisions that may have occurred after calling move_and_slide() and ensure that we collided with an enemy.

func stomp() -> void:
    # If we fell on top of an enemy, KinematicBody considers that we are on
    # the floor. We only run the stomp code if is_on_floor() returns true and
    # we're landing this frame.
    if not (is_landing() and is_on_floor()):
        return

    for index in get_slide_count():
        # We loop over all the collisions this frame and if one of the things we
        # collided with is an enemy, we destroy it and jump.
        var collision := get_slide_collision(index)
        # To detect enemies, we use a node group here, but you could also use
        # the is keyword and check for a specific type.
        #
        # Or you could use duck typing and check that the entity has a "die"
        # function for example.
        if collision.collider.is_in_group("enemy"):
            collision.collider.die()
            _velocity.y += stomp_bump_strength

Here, we extend our BasePlayerPlatformer3D class and call the parent class’s functions in _physics_process.

Afterward, we call the stomp function.

extends BasePlayerPlatformer3D

export var stomp_bump_strength := 4.0


func _physics_process(delta: float) -> void:
    apply_base_movement(delta)
    stomp()

If you use collision shapes other than boxes, is_on_floor() should work as long as the angle between your character’s shape and the enemy’s shape is less than the maximum slope angle at the collision point.

Moving platforms

You can use KinematicBody to create moving platforms. You can move them directly with move_and_slide(), like any moving entity in your world. You can also use the animation player to design moving platforms.

Each moving platform is a KinematicBody with an AnimationPlayer that animates its position. We use a looping animation for that.

In this case, you must use the Motion -> Sync to Physics option in the Inspector on the KinematicBody. It allows the physics engine to use changes in the node’s position when calculating collisions in the world.

Walking on rotating platforms

Building upon moving platforms, we can use KinematicBody to move on rotating surfaces.

Like with moving platforms, you can use the animation player to animate their rotation.

To do so, you want to set the animation player to update on the physics callback and enable the platforms Sync To Physics property to interact with the character correctly.

In our example, we created a bridge that can raise and prevent the player from crossing a gap.

We can set the angle of slope players can climb with the sixth parameter: floor_max_angle. This parameter takes a radian, so we pass in a maximum of 45 degrees and convert it to radians with the deg2rad() function.

To ensure the character actually slides on angled platforms, we need to set the 4th stop_on_slope argument in move_and_slide_snap() to false.

In our code, we use a property named do_stop_on_slope that we pass to move_and_slide_with_snap(). All we have to do is to toggle the property in the Inspector.

    _velocity = move_and_slide_with_snap(
        _velocity, _snap, Vector3.UP, do_stop_on_slope, 4, deg2rad(45), has_infinite_inertia
    )

Pushing rigid bodies

Many games involve pushing world objects around to solve physics puzzles, as in the 3D Legend of Zelda and Tomb Raider games.

This example is about having a push mechanic in your game where the character can stop against a rock and push it.

Here, we focus on pushing a RigidBody node: a rock controlled by the physics engine that keeps rolling after you push it.

Kinematic bodies can interact with other bodies. By default, if you call move_and_slide() with the infinite_inertia property set to true, your kinematic body can move any rigid body out of its way.

What if you want to stop when touching a RigidBody and control the pushing force instead?

To do so, you want to turn off infinite_inertia first. Since we’ve exposed the has_infinite_inertia property, we can set this in the Inspector on the player.

To push the body, we check if we are colliding with a rigid body, and if so, we apply an impulse to it in our direction of motion.

export var push_strength := 0.5

func push(delta: float) -> void:
    # We have to always reset the property to only set it to true when the
    # character is pushing something.
    _is_pushing = false
    for index in get_slide_count():
        var collision := get_slide_collision(index)
        var collider := collision.collider
        # We loop over all the collisions that occured this frame and look for a
        # RigidBody2D.
        if collider is RigidBody:
            # We ensure that one not above the body using a vector.product. We
            # use it to compare the angle between the floor normal and the
            # collision normal.
            #
            # A value lower than 0.9 means that the 2 vectors are at an angle
            # lower than 90°.
            _is_pushing = collision.normal.dot(Vector3.UP) < 0.9
            _velocity = _move_direction * push_strength
            # We apply an impulse to push the body we are colliding with.
            collider.apply_central_impulse(_velocity.normalized() * push_strength * delta)
            break
    _model.is_pushing = _is_pushing

We call our push() function in _physics_process().

func _physics_process(delta: float) -> void:
    apply_base_movement(delta)
    push(delta)

As we apply an impulse to the rocks, they keep rolling for a while even when we stop pushing. You can control their behavior more accurately with the many RigidBody properties.

We forward the _is_pushing property to the AstronautSkin scene so it can set the animation.

    _model.is_pushing = _is_pushing

Wall jumping

Wall jumping is an excellent addition to a 3D platformer, letting players reach new locales. The ability is pervasive in the genre and is present in the 3D Mario games, Tomb Raider, Ratchet and Clank, Prince of Persia, and many more.

Here, we have a character that can stick to walls, slide down, fall off, and wall jump.

Note: Any property we don’t show below here comes from the parent BasePlayerPlatformer3D class we showed before: Basic 3D Platformer movement.

We introduce a few new properties for the wall jump.

export var wall_friction_multiplier := 0.5

var _wall_normal: Vector3
var _input_direction: Vector3
var _wall_input: Vector3
var _is_locked_to_wall := false

onready var _wall_jump_timer: Timer = $WallJumpTimer

In the processing loop, we start by getting the camera-oriented input as usual.

    _input_direction = _get_camera_oriented_input()

Next, we check if the wall jump timer has stopped. If it has, we apply standard input to the character.

If the timer is running, then we are both on a wall and can wall jump. We apply a mix of the wall’s normal and the player’s input, fading it out with a lerp() function as the timer runs out. This mix locks the player’s movement to the direction of the wall jump for a time immediately after wall jumping.

func _physics_process(delta: float) -> void:
    # ...
    if _wall_jump_timer.is_stopped():
        _move_direction = _input_direction
    else:
        _move_direction = lerp(
            _input_direction, _wall_input, _wall_jump_timer.time_left / _wall_jump_timer.wait_time
        )

Before checking whether we are locked into wall sliding, we need to know the normal of any wall we are touching.

Here is the logic for setting the _is_locked_to_wall variable and applying some friction to the character if they are wall sliding, using several Boolean functions.

    _wall_normal = get_wall_normal()

    if _is_locked_to_wall:
        _is_locked_to_wall = not is_pressing_away_from_wall()
    else:
        _is_locked_to_wall = is_on_wall() and is_pressing_against_wall()

    if is_wall_sliding():
        # We apply some friction to slow down the character's fall.
        _velocity *= wall_friction_multiplier
        # And we push the character towards the wall to make them stick to it.
        _velocity += _wall_normal * _gravity * delta

We check our jumping and landing Boolean functions with the addition of is_wall_jumping().

    if is_jumping():
        _velocity.y = jump_initial_impulse
        _snap = Vector3.ZERO
        _model.jump()
    elif is_wall_jumping():
        _wall_jump_timer.start()
        _velocity.y = jump_initial_impulse
        _wall_input = _wall_normal
        _snap = Vector3.ZERO
        _model.jump()
    elif is_air_boosting():
        _velocity.y += jump_additional_force * delta
    elif is_landing():
        _snap = Vector3.DOWN * snap_length
        _model.land()

Finally, we call move_and_slide_with_snap() to move the character.

func _physics_process(delta: float) -> void:
  # ...
    _velocity = move_and_slide_with_snap(
        _velocity, _snap, Vector3.UP, do_stop_on_slope, 4, deg2rad(45), has_infinite_inertia
    )
    _model.velocity = _velocity

Here are the functions that tell us if the character has just fallen, is wall jumping, or is sliding on a wall.

## Returns `true` if the character starts falling.
func is_just_falling() -> bool:
    return not _anim_player.current_animation == "fall" and is_falling()


## Returns `true` if the character is initiating a wall-jump.
func is_wall_jumping() -> bool:
    return is_on_wall() and Input.is_action_just_pressed("jump")


## Returns `true` if the character is sliding against a wall.
func is_wall_sliding() -> bool:
    return is_on_wall() and not is_zero_approx(_horizontal_direction)

First Person Controller

To finish up, we’ll show a simple example of a first-person controller using KinematicBody.

Here we are using the common FPS controller used in several other demos. Its located in common/PlayerFPS3D.

Using KinematicBody for an FPS is much the same as using it for a third person controller.

While the player script directly controls the Camera for the FPS controller, the basics are the same.

func _physics_process(delta: float) -> void:
    # ...
func _input(event: InputEvent) -> void:
    if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
        _yaw_input = -event.relative.x * mouse_sensitivity
        _tilt_input = -event.relative.y * mouse_sensitivity

We get the input and align it to the player. Then, we calculate the velocity.

    var input := Vector3.ZERO
    input.x = raw_input.x * sqrt(1.0 - raw_input.y * raw_input.y / 2.0)
    input.z = raw_input.y * sqrt(1.0 - raw_input.x * raw_input.x / 2.0)

    input = global_transform.basis.xform(input)

    var y_velocity := _velocity.y
    _velocity.y = 0.0
    _velocity = _velocity.linear_interpolate(input * move_speed, delta * acceleration)
    _velocity.y = y_velocity

We use bool functions to check for jumping and landing.

    if is_jumping():
        _velocity.y = jump_impulse
        _snap = Vector3.ZERO
    elif is_landing():
        _snap = Vector3.DOWN * snap_length

And we use move_and_slide_with_snap() to move the controller.

    _velocity = move_and_slide_with_snap(
        _velocity, _snap, Vector3.UP, true, 4, deg2rad(45), true
    )

Your questions

When should I pick KinematicBody over other physics bodies and areas?

KinematicBody is excellent for any physical object you want to move manually with fine control. KinematicBody is the most commonly used node for characters in Godot.

Here is when you should use StaticBody, RigidBody, or Area instead:

Use a StaticBody for solid walls or ground, even for objects that affect the player’s movement, like conveyor belts.

Use a RigidBody for any physical object you want to move using physics properties like gravity and forces.

While you typically use them for physics games, some studios also use rigid body physics for all their game characters.

Unlike the above, Area does not handle collisions with the environment. It only detects what enters and leaves it, whether it’s another area, a physics body, or the mouse cursor.

You can use it whenever you need to have something happen when entering or touching an entity, but you don’t need collisions. You’ll find many examples of that in the Area guide.

When should I use move_and_collide() over the easier move_and_slide()?

Godot used to only have move_and_collide() until version 2.0. Later, the developers added the move_and_slide() function to handle the most common ways people moved characters with a KinematicBody.

Often, move_and_slide() is all you need as it gives you several parameters to customize how the motion feels.

However, it doesn’t handle all the possible motions you would want for your games.

For one, you can’t use it to create mirroring lasers and other objects that bounce against walls. Although, if the shape of the projectile does not matter, you can use a RayCast instead.

For custom use cases move_and_collide() might be needed.

In any case, we recommend trying to use move_and_slide() or move_and_slide_with_snap() and only switch to move_and_collide() when they show their limits. They are both easy to replace as they often are just one function call in your character script.

How do I control what my kinematic body collides with?

As with every other physics body or area, you want to use the physics layers and masks to control what your entity collides with.

Your body collides with every physics layer set in its mask property.

If you want to react to a collision with a specific body, there are a few strategies you can use to check which body you collided with specifically:

We detailed those strategies and their pros and cons in the Area guide: telling-bodies-apart.

Lastly, you can register exceptions, other bodies on a layer that you want to ignore.

For example, in a game with a non-playable character that accompanies the hero, you might want to ignore collisions with that NPC for a short time during certain scenes or interactions.

When that is the case, you can use the function to add and then remove an exception.

add_collision_exception_with(npc)

remove_collision_exception_with(npc)

When would I use test_move()?

The KinematicBody class has a test_move function that we rarely use, which can be very useful, especially when polishing your game.

You can think of it like a RayCast, but that projects your whole character’s collision shapes instead of just a line.

One use case would be to prevent a character from ending a dash inside a wall: by testing the motion in advance, we know the character cannot get stuck regardless of the dash angle.

In Unity tutorials, you’ll sometimes see people use many ray casts to make platform characters move and detect features of the environment.

You can often use a single KinematicBody node and test_move() instead in Godot.

If the test motion would cause a collision, the function returns false. Otherwise, it returns true.